#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>
#include<signal.h>
#define N 128

#define ERRLOG(errmsg) do{\
                            perror(errmsg);\
                            printf("file : %s, func: %s, line : %d", __FILE__, __func__, __LINE__);\
                            exit(-1);\
                        }while(0);

#define NONE "\e[0m"

#define L_RED "\e[1;31m"

#define printlr(format, arg...) do{printf(L_RED format NONE, ## arg);}while(0)

typedef struct{
    int code;
    char name[32];
    char text[32];
}MSG;

int main(int argc, char const *argv[]){
    if(argc != 3){
        fprintf(stderr, "Usage %s <ip> <port>\n", argv[0]);
        exit(-1);
    }
    int sockfd = -1;
    struct sockaddr_in servaddr;
    socklen_t addrlen = sizeof(servaddr);
    if((sockfd  = socket(AF_INET, SOCK_DGRAM, 0)) == -1){
        ERRLOG("socket error");
    }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr(argv[1]);
    servaddr.sin_port = htons(atoi(argv[2]));

    MSG msg;
    memset(&msg, 0, sizeof(msg));

    while(1){
        //登陆操作
        msg.code = 1;
        //设置用户名
        printf("请输入用户名: ");
        fgets(msg.name, 32, stdin);
        msg.name[strlen(msg.name) - 1] = '\0';
        //发送数据
        if(sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&servaddr, addrlen) == -1){
            ERRLOG("sendto error");
        }
        if(recvfrom(sockfd, &msg, sizeof(msg), 0, NULL, NULL) == -1){
            ERRLOG("recvfrom error");
        }
        printf("%s\n", msg.text);
        if(msg.code == 1){
            break;
        }
    }
    //创建子进程实现一边发送数据一边接收数据
    pid_t pid;
    if((pid = fork()) == -1){
        ERRLOG("fork error");
    }else if(pid > 0){
        while(1){
            fgets(msg.text, 32, stdin);
            msg.text[strlen(msg.text) - 1] = '\0';

            //退出操作
            if(strcmp(msg.text, "quit") == 0){
                //设置操作为3 —— 代表退出操作
                msg.code = 3;
                //将组号的数据发送给服务器
                if(sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&servaddr, addrlen) == -1){
                    ERRLOG("sendto error");
                }
                //先让子进程提出
                kill(pid, SIGKILL);
                //父进程也退出
                exit(0);
            }else if(strncmp(msg.text, "private to ", strlen("private to ")) == 0){
                //设置操作码为4 —— 代表私聊操作
                msg.code = 4;
            }else{
                msg.code = 2;
            }
            //将组号的数据发送给服务器
            if(sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&servaddr, addrlen) == -1){
                ERRLOG("sendto error");
            }
        }
    }else{
        //子进程接收数据
        while(1){
            if(recvfrom(sockfd, &msg, N, 0, NULL, NULL) == -1){
                ERRLOG("recvfrom error");
            }
            if(msg.code == 4){
                printlr("%s%s\n", msg.name, msg.text);
                fflush(stdout);
            }else{
                printf("%s\n", msg.text);
            }
        }
    }
    return 0;
}